<html>

<head>
<title>WebGL game lib</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">

<script type="text/javascript" src="../src/catgl.js"></script>
<script type="text/javascript" src="../src/glMatrix.js"></script>
<script type="text/javascript" src="../src/glMatrixPlus.js"></script>
<script type="text/javascript" src="../src/curve.js"></script>
<script type="text/javascript" src="../src/camera.js"></script>
<script type="text/javascript" src="../src/key.js"></script>
<script type="text/javascript" src="../src/matrixstack.js"></script>
<script type="text/javascript" src="../src/shaderManager.js"></script>
<script type="text/javascript" src="../src/actor.js"></script>
<script type="text/javascript" src="../src/framerate.js"></script>
<script type="text/javascript" src="../src/models.js"></script>
<script type="text/javascript" src="../src/mouse.js"></script>
<script type="text/javascript" src="../src/lightManager.js"></script>

<script type="text/javascript" src="../resource/myMiku.js"></script>


<script type="text/javascript">

    // Key入力の設定
    function setupKey()
    {
        var keyManager = catGL.keyManager;
        // 押した瞬間の処理
        keyManager.setDownCallback(function(c){
                var camera = catGL.camera;
                // ネギ発射
                if (String.fromCharCode(c) == "N"){

                }
                //alert(c);
                });
       // 押されている間中起こる処理
       keyManager.setIntervalCallback(15, function(){
                var camera = catGL.camera;
                var mikuMatrix = catGL.app.actorMiku.matrix;
                var v = vec3.create();
                var mvf = vec3.create([0,0,0.5]);
                var mvb = vec3.create([0,0,-0.25]);
                // 左
                if (keyManager.keyPressed[37]){
                    mat4.rotateY(mikuMatrix, 5*Math.PI/180);
                }
                // 右
                if (keyManager.keyPressed[39]){
                    mat4.rotateY(mikuMatrix, -5*Math.PI/180);
                }
                // 上 
                if (keyManager.keyPressed[38]){
                    mat4.calcLocalVec3(mikuMatrix, mvf, v);
                    mat4.move(mikuMatrix, mvf);
                    vec3.add(camera.eye_pos, v);
                }
                // 下
                if (keyManager.keyPressed[40]){
                    mat4.calcLocalVec3(mikuMatrix, mvb, v);
                    mat4.move(mikuMatrix, mvb);
                    vec3.add(camera.eye_pos, v);
                }
                // N
                if (keyManager.keyPressed[78]){
                    var matrix = catGL.app.actorMiku.getNegiWorldMatrix();
                    var actorNegi = Actor.create(matrix, catGL.app.modelNegi);
                    var moveVect = vec3.create();
                    var speed = 4;
                    var g = -0.098;
                    moveVect[0] = -matrix[4] * speed;
                    moveVect[1] = -matrix[5] * speed;
                    moveVect[2] = -matrix[6] * speed;
                    catGL.app.negiCnt += 1;

                    actorNegi.exec = function(){
                        if (this.matrix[13] > 6){
                            this.matrix[12] += moveVect[0];
                            this.matrix[13] += moveVect[1];
                            this.matrix[14] += moveVect[2];
                            mat4.rotateX(this.matrix, 4*Math.PI/180);
                            moveVect[1] += g;
                            //catGL.actorManager.deleteActor(this);
                        }
                    }
                    catGL.actorManager.addActor(actorNegi);
                }
            });
    }

    // Mouseの機能の登録
    function setupMouse(){
        var mouseManager = catGL.mouseManager;
        var camera = catGL.camera;
        var keyManager = catGL.keyManager;
        var app = catGL.app;
        var mikuMatrix = app.actorMiku.matrix;
        var arg = {};

        // ホイールでカメラ前後
        arg.scrollWheel = function(delta){
            camera.move(0,0,-delta*0.05);
        }
        arg.moveMouse = function(x, y, offsetX, offsetY){
            // 左クリック状態のmouse移動
            if (mouseManager.buttonPressed[0]){
                //if (keyManager.keyPressed[90]){  
                //    // zキーが押されていればカメラの回転
                //    camera.yaw(-offsetX * 4*Math.PI/180);
                //    camera.pitch(offsetY * 4*Math.PI/180);
                //} else { 
                //    // 押されていなければカメラの移動
                //    camera.move(offsetX * 0.05, -offsetY * 0.05, 0);
                //    lookAtMiku();
                //}
                var rvect = vec3.create();
                var temp = vec3.create();
                var temp2 = vec3.create();
                var rvectLen = vec3.create();
                var target = vec3.create();
                var pos = vec3.create();
                mat4.multiplyVec3(mikuMatrix, 
                        app.lookAtMiku, target);
                // 左右方向のカメラ移動
                vec3.subtract(camera.eye_pos, target, rvect);
                var matY = mat4.createRotateY(-offsetX * 0.01);
                mat4.multiplyVec3(matY, rvect, rvectLen);
                vec3.add(target, rvectLen, camera.eye_pos);
                vec3.normalize(rvectLen, camera.eye_rvect);

                // 上下方向のカメラ移動
                vec3.subtract(camera.eye_pos, target, rvect);
                var len = vec3.length(rvect);
                var matrix = mat4.createRotateX(offsetY * 0.01);
                var cmatrix = camera.toMatrix();
                mat4.multiply(matrix, cmatrix);
                rvect[0] = matrix[2];
                rvect[1] = matrix[6];
                rvect[2] = matrix[10];
                var chkVec0 = vec2.create([1, 0]);
                var chkVec1 = vec2.create();
                chkVec1[0] = Math.sqrt(rvect[0]*rvect[0]+rvect[2]*rvect[2]);
                chkVec1[1] = rvect[1];
                var angle = vec2.calcAngle(chkVec0, chkVec1);
                if (angle <= 80 * Math.PI / 180){
                    vec3.scale(rvect, len, rvectLen);
                    vec3.add(target, rvectLen, pos);
                    if (pos[1] > 0){
                        vec3.set(pos, camera.eye_pos);
                        vec3.set(rvect, camera.eye_rvect);
                    }
                }
            }
        }
        // センターを押すとカメラを初期値へ
        //arg.downCenter = function(){
        //    vec3.set([0, 0, 0], camera.eye_pos);
        //    vec3.set([0, 0, 1], camera.eye_rvect);
        //}
        mouseManager.setCallbackFunction(arg);
    }

    // 登場するアクアーの登録
    function setActors(){
        var gl = catGL.gl;
        var actorManager = catGL.actorManager;

        // Miku 
        //var mikuModel = createBlenderModel(MyExportMiku, MyExportMiku.miku_far, "texture-v-Light");
        var mikuModel = createBlenderModel(MyExportMiku, MyExportMiku.miku_far, 
                function(model){return "texture-v-Light";});
        catGL.app.modelMiku = mikuModel;
        //mikuModel.setShaderName("material");
        var actorMiku = Actor.create(
                mat4.createI(),
                mikuModel);
        actorMiku.exec = function(){
            var angle = 0;
            var speed = 10;
            var baseMatrix = mat4.create(actorMiku.model.child[0].child[0].matrix);
            return function(){
                var rArmMatrix = this.model.child[0].child[0].matrix;
                // 全身の回転
                //mat4.rotateY(this.matrix, 0.5*Math.PI/180);
                // 腕の回転
                var r = -40 + 90 * (Math.sin(angle*Math.PI/180) + 1)*0.5;
                angle += speed;

                mat4.rotateX(baseMatrix, r*Math.PI/180, rArmMatrix);
            }
        }();
        actorManager.addActor(actorMiku);
        actorMiku.matrixStack = MatrixStack.create();
        // ネギのworld行列を取得する
        actorMiku.getNegiWorldMatrix = function(){
            var matrixStack = this.matrixStack;
            var child;
            matrixStack.init();
            matrixStack.push(this.matrix);
            matrixStack.push(this.model.matrix);
            // miku nearモデル
            child = this.model.child[0];
            //  miku r armモデル
            child = child.child[0];
            matrixStack.push(child.matrix);
            //  negiモデル
            child = child.child[0];
            matrixStack.push(child.matrix);

            return mat4.create(matrixStack.top());
        }
        catGL.app.actorMiku = actorMiku;

        // axisモデル(三色) 
        var axisModel = createAxisModel(10);
        var actorAxis = Actor.create(
                mat4.createI(),
                axisModel);
        actorManager.addActor(actorAxis);

        // ネギモデル（表示登録はしない）
        //catGL.app.modelNegi = createBlenderModel(BlenderExport.miku2.negi, 1);
        catGL.app.modelNegi = createBlenderModel(MyExportMiku, MyExportMiku.negi,
                function(model){return "texture-v-Light";}, 1);

        // 地面
        var fieldModel = createCircleModel([0,0,0], 100, 30, 
                [1, 0.5, 0, 1],[0, 0, 0, 1]);
        var actorField = Actor.create(mat4.createI(), fieldModel);
        actorManager.addActor(actorField);
    }

    function appLoop() {
        var app = catGL.app;
        var negi_cnt = document.getElementById("negi_cnt");
        negi_cnt.innerHTML = "ネギ=" + app.negiCnt + "本";
    }

    function lookAtMiku(){
        var pos = vec3.create();
        var app = catGL.app;
        mat4.multiplyVec3(app.actorMiku.matrix, 
                app.lookAtMiku, pos);
        catGL.camera.lookAtVec3(pos);
    }

    function webGLStart() {
        var canvas = document.getElementById("test-canvas");

        // gl contextの初期化
        catGL.init(canvas, {
                    zfar: 1000,
                    framerate_id:"fr",
                    framerate_updateInterval: 500,
                    //draw_model_axis: true,
                    axis_length: 3
                    });

        // 初期カメラ位置
        vec3.set([0, 14, -60], catGL.camera.eye_pos);
        
        // applicationデータの登録先
        catGL.app = {};
        catGL.app.negiCnt = 0;
        // lookAt座標（Mikuの座標系）
        catGL.app.lookAtMiku = vec3.create([0,16,0]);

        // shader managerの初期化
        var shaderManager;
        shaderManager = catGL.shaderManager;
        shaderManager.loadShader("vertex-color");
        shaderManager.loadShader("material");
        shaderManager.loadShader("material-v-Light");
        shaderManager.loadShader("material-v-LightSpec");
        shaderManager.loadShader("material-f-LightSpec");
        shaderManager.loadShader("texture");
        shaderManager.loadShader("texture-v-Light");
        shaderManager.loadShader("texture-v-LightSpec");
        shaderManager.loadShader("texture-f-LightSpec");

        // ライティングに関する設定のshaderへの設定
        //shaderManager.loadLightParam();
        
        // 登場するアクターの登録
        setActors();

        // UIと同じshaderを設定する
        shaderSelect();

        // Key入力の設定
        setupKey();

        // Mouse入力の設定
        setupMouse();

        // Mikuを向かせる
        lookAtMiku();

        // Mikuの背中を追尾するカメラ
        catGL.camera.animation_que.push(function(){
                var target= vec3.create();
                var app = catGL.app;
                var camera = catGL.camera;
                var mikuMatrix = app.actorMiku.matrix;
                mat4.multiplyVec3(mikuMatrix, 
                        app.lookAtMiku, target);
                
                var curVec = vec3.create();// 現在のカメラ位置へのベクトル
                vec3.subtract(camera.eye_pos, target, curVec);
                var xzLen = Math.sqrt(curVec[0]*curVec[0]+curVec[2]*curVec[2]);
                var tempVec = vec3.create();
                tempVec[0] = 0;
                tempVec[1] = curVec[1];
                tempVec[2] = -xzLen;
                
                var goalVec = vec3.create();// 目指すべきカメラへのベクトル
                mat4.calcLocalVec3(mikuMatrix, tempVec, goalVec);

                if (goalVec[0] != curVec[0] || goalVec[2] != curVec[2]){
                    var rotVec = vec3.create();
                    var limitAngle = 1.5*Math.PI/180;
                    // 回転方向の確認
                    // 2次元のXY平面で考えるのでZを反転している
                    var chkVec0 = vec2.create([curVec[0], -curVec[2]]);
                    var chkVec1 = vec2.create([goalVec[0], -goalVec[2]]);
                    var angle = vec2.calcAngle(chkVec0, chkVec1);
                    if (Math.abs(angle) > limitAngle){
                        if (angle < 0){
                            angle = -limitAngle;
                        } else {
                            angle = limitAngle;
                        }
                        var rotMat = mat4.createRotateY(angle);
                        mat4.multiplyVec3(rotMat, curVec, goalVec);
                    }
                    vec3.add(target, goalVec, camera.eye_pos);
                    vec3.normalize(goalVec, camera.eye_rvect);
                }
                    

                return true;
            });

        // UIのセットアップ
        var obj = document.getElementsByClassName("color");
        for (var i = 0; i < obj.length; i++) {
            obj[i].addEventListener("change",function(){
                    changeLightColor();
                    })
        }
        function changeLightColor() {
            var r = document.getElementById("ambR").value;
            var g = document.getElementById("ambG").value;
            var b = document.getElementById("ambB").value;
            catGL.lightManager.setAmbLightColor(([r*0.01, g*0.01, b*0.01]));
            var color = (parseInt(r * 2.55) << 16)|(parseInt(g*2.55)<<8)|(parseInt(b*2.55));
            var colorStr = color.toString(16);
            document.getElementById("ambColor").style.backgroundColor = 
                    "#000000".slice(0,7-colorStr.length)+colorStr;
            r = document.getElementById("dirDiffR").value;
            g = document.getElementById("dirDiffG").value;
            b = document.getElementById("dirDiffB").value;
            catGL.lightManager.setDirLightDiffColor(([r*0.01, g*0.01, b*0.01]));
            color = (parseInt(r * 2.55) << 16)|(parseInt(g*2.55)<<8)|(parseInt(b*2.55));
            colorStr = color.toString(16);
            document.getElementById("dirDiffColor").style.backgroundColor = 
                    "#000000".slice(0,7-colorStr.length)+colorStr;
            r = document.getElementById("dirSpecR").value;
            g = document.getElementById("dirSpecG").value;
            b = document.getElementById("dirSpecB").value;
            catGL.lightManager.setDirLightSpecColor(([r*0.01, g*0.01, b*0.01]));
            color = (parseInt(r * 2.55) << 16)|(parseInt(g*2.55)<<8)|(parseInt(b*2.55));
            colorStr = color.toString(16);
            document.getElementById("dirSpecColor").style.backgroundColor = 
                    "#000000".slice(0,7-colorStr.length)+colorStr;
        }
        // 初回の色の設定
        changeLightColor();

        // MainLoopの開始
        catGL.start(15, appLoop);
    }
function shaderSelect() {
    var selectMenu = document.getElementById("shaderSelect");
    //alert(selectMenu.value);
    catGL.app.modelMiku.setShaderName(selectMenu.value);
    catGL.app.modelNegi.setShaderName(selectMenu.value);
    
}

</script>
<style TYPE="text/css">
.ambColor{
    width:150px;
    height:20px;
    border-color:#000000;
    border-width:1px;
    border-style:solid;
}
.dirDiffColor{
    width:150px;
    height:20px;
    border-color:#000000;
    border-width:1px;
    border-style:solid;
}
.dirSpecColor{
    width:150px;
    height:20px;
    border-color:#000000;
    border-width:1px;
    border-style:solid;
}
</style>
</head>
<body onload="webGLStart();" onselectstart="return false;">
    <table>
        <tr>
            <td>
                <canvas id="test-canvas" style="border: none;" width="640" height="480"></canvas>
            </td>
            <td>
                <h4>操作方法</h4>
                カメラをマウスとキーボードから動かせます<br>
                <ul>
                    <li>左ボタン＋マウス移動：カメラの移動</li>
                    <li>マウスのホイール操作：カメラの前後の移動</li>
                    <li>n：ネギを飛ばすく</li>
                    <li>カーソルキー：ミクの移動</li>
                </ul>
            </td>
        </tr>
    </table>
    <div id="fr"></div>
    <div id="negi_cnt"></div>
    <select id="shaderSelect" size=1 onchange="shaderSelect();">
        <option value="material">マテリアルの色
        <option value="material-v-Light">マテリアルの色と平行光源(amb,diff) vertex shaderでの計算
        <option value="material-v-LightSpec">マテリアルの色と平行光源(amb,diff,spec) vertex shaderでの計算
        <option value="material-f-LightSpec">マテリアルの色と平行光源(amb,diff,spec) fragment shaderでの計算
        <option value="texture" selected="selected">texture
        <option value="texture-v-Light">textureと平行光源(amb,diff) vertex shaderでの計算
        <option value="texture-v-LightSpec">textureと平行光源(amb,diff,spec) vertex shaderでの計算
        <option value="texture-f-LightSpec">textureと平行光源(amb,diff,spec) fragment shaderでの計算
    </select>
    <table>
        <tr>
            <td>
                <ul>
                    Ambient Light
                    <li>R<input type="range" id="ambR" min="0" max="100" value="30" class="color"></li>
                    <li>G<input type="range" id="ambG" min="0" max="100" value="30" class="color"></li>
                    <li>B<input type="range" id="ambB" min="0" max="100" value="30" class="color"></li>
                    <li><div class="ambColor" id="ambColor"></div></li>
                </ul>
            </td>
            <td>
                <ul>
                    Direction Light(diffuse)
                    <li>R<input type="range" id="dirDiffR" min="0" max="100" value="70" class="color"></li>
                    <li>G<input type="range" id="dirDiffG" min="0" max="100" value="70" class="color"></li>
                    <li>B<input type="range" id="dirDiffB" min="0" max="100" value="70" class="color"></li>
                    <li><div class="dirDiffColor" id="dirDiffColor"></div></li>
                </ul>
            </td>
            <td>
                <ul>
                    Direction Light(specular)
                    <li>R<input type="range" id="dirSpecR" min="0" max="100" value="70" class="color"></li>
                    <li>G<input type="range" id="dirSpecG" min="0" max="100" value="70" class="color"></li>
                    <li>B<input type="range" id="dirSpecB" min="0" max="100" value="70" class="color"></li>
                    <li><div class="dirSpecColor" id="dirSpecColor"></div></li>
                </ul>
            </td>
        </tr>
    </table>
</body>
</html>

